home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 039a / mawk10.zip / SCAN.C < prev    next >
C/C++ Source or Header  |  1991-10-05  |  23KB  |  835 lines

  1.  
  2. /********************************************
  3. scan.c
  4. copyright 1991, Michael D. Brennan
  5.  
  6. This is a source file for mawk, an implementation of
  7. the AWK programming language.
  8.  
  9. Mawk is distributed without warranty under the terms of
  10. the GNU General Public License, version 2, 1991.
  11. ********************************************/
  12.  
  13.  
  14. /* $Log:    scan.c,v $
  15.  * Revision 3.7.1.1  91/09/14  17:24:11  brennan
  16.  * VERSION 1.0
  17.  * 
  18.  * Revision 3.7  91/08/13  06:52:04  brennan
  19.  * VERSION .9994
  20.  * 
  21.  * Revision 3.6  91/07/19  07:51:28  brennan
  22.  * escape sequence now recognized in command line assignments
  23.  * 
  24.  * Revision 3.5  91/06/29  09:47:27  brennan
  25.  * Only track NR if needed
  26.  * 
  27.  * Revision 3.4  91/06/28  04:17:31  brennan
  28.  * VERSION 0.999
  29.  * 
  30.  * Revision 3.3  91/06/24  07:18:40  brennan
  31.  * no longer recognize \'
  32.  * 
  33.  * Revision 3.2  91/06/15  09:05:16  brennan
  34.  * some casting of [unsigned] char* to make gcc happy
  35.  * 
  36.  * Revision 3.1  91/06/07  10:28:15  brennan
  37.  * VERSION 0.995
  38.  * 
  39.  * Revision 2.9  91/06/06  09:42:08  brennan
  40.  * added HAVE_FCNTL
  41.  * 
  42.  * Revision 2.8  91/06/04  06:47:34  brennan
  43.  * removed <string.h>
  44.  * 
  45.  * Revision 2.7  91/06/03  07:51:21  brennan
  46.  * added work around for sun4, 4.0.3, strtod() bug
  47.  * scanner eats semi-colons in outer blocks for compatibility
  48.  * 
  49.  * Revision 2.6  91/05/29  14:26:09  brennan
  50.  * -V option for version
  51.  * 
  52.  * Revision 2.5  91/05/28  15:18:13  brennan
  53.  * removed STRING_BUFF back to temp_buff.string_buff
  54.  * 
  55.  * Revision 2.4  91/05/28  09:05:11  brennan
  56.  * removed main_buff
  57.  * 
  58.  * Revision 2.3  91/04/29  07:47:23  brennan
  59.  * INC_or_DEC to support grammar changes
  60.  * 
  61.  * Revision 2.2  91/04/09  12:39:27  brennan
  62.  * added static to funct decls to satisfy STARDENT compiler
  63.  * 
  64.  * Revision 2.1  91/04/08  08:23:51  brennan
  65.  * VERSION 0.97
  66.  * 
  67. */
  68.  
  69.  
  70. #include  "mawk.h"
  71. #include  "sizes.h"
  72. #include  "scan.h"
  73. #include  "memory.h"
  74. #include  "field.h"
  75. #include  "init.h"
  76. #include  "fin.h"
  77. #include  "repl.h"
  78.  
  79. #if HAVE_FCNTL_H
  80. #include  <fcntl.h>
  81. #endif
  82.  
  83. #include  "files.h"
  84.  
  85.  
  86. /* static functions */
  87. static void PROTO(buff_create, (char *) ) ;
  88. static int PROTO(slow_next, (void) ) ;
  89. static void PROTO(eat_comment, (void) ) ;
  90. static void PROTO(eat_semi_colon, (void) ) ;
  91. static double PROTO(collect_decimal, (int, int *) ) ;
  92. static int PROTO(collect_string, (void) ) ;
  93. static int  PROTO(collect_RE, (void) ) ;
  94.  
  95. extern  short  NR_reference ;
  96.  
  97. /*-----------------------------
  98.   program file management
  99.  *----------------------------*/
  100.  
  101. static  unsigned char *buffer ;
  102. static  unsigned char *buffp ;  
  103.     /* unsigned so it works with 8 bit chars */
  104. static  int  program_fd = -1  ; 
  105. static  int  eof_flag ;
  106.  
  107.  
  108. static void buff_create(s)
  109.   char *s ;
  110. {
  111.   /* If program_fd == -1, program came from command line and s
  112.      is it, else s is a filename */
  113.  
  114.   if ( program_fd == -1 )
  115.   { buffer = buffp = (unsigned char *) s ; eof_flag = 1 ; }
  116.   else /* s is a filename, open it */
  117.   {
  118.     if ( s[0] == '-' && s[1] == 0 ) program_fd = 0 ;
  119.     else
  120. #ifdef THINK_C
  121.     if ( (program_fd = open(s, O_RDONLY)) == -1 )
  122. #else
  123.     if ( (program_fd = open(s, O_RDONLY, 0)) == -1 )
  124. #endif
  125.     { errmsg( errno, "cannot open %s", s) ; mawk_exit(1) ; }
  126.  
  127.     buffp = buffer = (unsigned char *) zmalloc( BUFFSZ+1 ) ;
  128.  
  129.     eof_flag = fillbuff(program_fd, (char *) buffer, BUFFSZ) < BUFFSZ ;
  130.   }
  131. }
  132.  
  133. void scan_cleanup()
  134.   if ( program_fd >= 0 ) zfree(buffer, BUFFSZ+1) ;
  135.   if ( program_fd > 0 )  (void) close(program_fd) ;
  136.   /* redefine SPACE as [ \t\r\n] */
  137.   scan_code['\n'] = SC_SPACE ;
  138.   scan_code['\f'] = SC_UNEXPECTED ; /*value doesn't matter */
  139.   scan_code['\013'] = SC_UNEXPECTED ;
  140. }
  141.  
  142.  
  143. void  scan_init(flag, p)
  144.   int flag ; /* on if program is from the command line */
  145.   char *p ;
  146.   if ( ! flag ) program_fd = 0 ;
  147.   buff_create(p) ;
  148.  
  149.   eat_nl() ; /* scan to first token */
  150.   if ( next() == 0 )  
  151.   { errmsg(0, "no program") ; mawk_exit(1) ; }
  152.   un_next() ;
  153. }
  154.  
  155. /*--------------------------------
  156.   global variables shared by yyparse() and yylex()
  157.  *-------------------------------*/
  158.  
  159. int  current_token = -1 ; 
  160. unsigned  token_lineno ;
  161. unsigned  compile_error_count ;
  162. int   paren_cnt ;
  163. int   brace_cnt ;
  164. int   print_flag ;  /* changes meaning of '>' */
  165. int   getline_flag ; /* changes meaning of '<' */
  166.  
  167. extern  YYSTYPE  yylval ;
  168.  
  169. /*----------------------------------------
  170.  file reading functions
  171.  next() and un_next(c) are macros in scan.h
  172.  
  173.  *---------------------*/
  174.  
  175. static  unsigned lineno = 1 ;
  176.  
  177. /* used to help distinguish / as divide or start of RE  */
  178.  
  179. static int can_precede_re[] =
  180. { MATCH, NOT_MATCH, COMMA, RBRACE, 
  181. LPAREN, NOT, P_OR, P_AND, NL,  -1 } ;
  182.  
  183. /* read one character -- slowly */
  184. static int slow_next()
  185.   if ( *buffp == 0  )
  186.       if ( !eof_flag ) 
  187.       { buffp = buffer ;
  188.         eof_flag = fillbuff(program_fd, (char *)buffer,BUFFSZ) < BUFFSZ ;
  189.       }
  190.  
  191.   return *buffp++ ; /* note can un_next() , eof which is zero */
  192. }
  193.  
  194. static void eat_comment()
  195. { register int c ;
  196.  
  197.   while ( (c = next()) != '\n' && scan_code[c] ) ;
  198.   un_next() ;
  199. }
  200.  
  201. /* this is how we handle extra semi-colons that are
  202.    now allowed to separate pattern-action blocks
  203.  
  204.    A proof that they are useless clutter to the language:
  205.    we throw them away
  206. */
  207.  
  208. static  void  eat_semi_colon()
  209. /* eat one semi-colon on the current line */
  210. { register int c ;
  211.  
  212.   while ( scan_code[c = next()] == SC_SPACE )  ;
  213.   if ( c != ';' )  un_next() ;
  214. }
  215.  
  216. void eat_nl() /* eat all space including newlines */
  217. {
  218.   while ( 1 )
  219.     switch( scan_code[next()] )
  220.     { 
  221.       case SC_COMMENT : 
  222.          eat_comment() ;
  223.          break ;
  224.          
  225.       case  SC_NL  :   lineno++ ;
  226.       /* fall thru  */
  227.       case  SC_SPACE  :   break ;
  228.       default :  
  229.           un_next() ; return ;
  230.     }
  231. }
  232.  
  233. int yylex()
  234.   register int c ;
  235.  
  236.   token_lineno = lineno ;
  237.  
  238. reswitch:
  239.  
  240.     switch( scan_code[c = next()] )
  241.     {
  242.       case  0  :  /* if no terminator on the line put one */
  243.           if ( (c = current_token) == RBRACE ||
  244.                 c == NL || c == SEMI_COLON ) ct_ret(EOF) ;
  245.           else
  246.           { un_next() ;  ct_ret(NL) ; }
  247.           
  248.       case  SC_SPACE  :   goto reswitch ;
  249.  
  250.       case  SC_COMMENT :
  251.           eat_comment() ; goto reswitch ;
  252.  
  253.       case  SC_NL  : 
  254.           lineno++ ; eat_nl() ;
  255.           ct_ret(NL) ;
  256.  
  257.       case SC_ESCAPE :
  258.           while ( scan_code[ c = next() ] == SC_SPACE ) ;
  259.           if ( c == '\n')
  260.           { token_lineno = ++lineno ; goto reswitch ; }
  261.           if ( c == 0 )  ct_ret(EOF) ;
  262.           un_next() ;
  263.           yylval.ival = '\\' ;
  264.           ct_ret(UNEXPECTED) ;
  265.  
  266.  
  267.       case  SC_SEMI_COLON  : 
  268.           eat_nl() ;
  269.           ct_ret(SEMI_COLON) ;
  270.  
  271.       case  SC_LBRACE :  
  272.           eat_nl() ; brace_cnt++ ;
  273.           ct_ret(LBRACE) ;
  274.  
  275.       case  SC_PLUS  :
  276.           switch( next() )
  277.           {
  278.             case '+' :  
  279.                 yylval.ival = '+' ;
  280.                 temp_buff.string_buff[0] = 
  281.                      temp_buff.string_buff[1] = '+' ;
  282.                 temp_buff.string_buff[2] = 0 ;
  283.                 ct_ret(INC_or_DEC) ;
  284.  
  285.             case  '=' :
  286.                 ct_ret(ADD_ASG) ;
  287.  
  288.             default :  un_next() ; ct_ret(PLUS) ;
  289.           }
  290.  
  291.       case  SC_MINUS :
  292.           switch( next() )
  293.           {
  294.             case '-' :  
  295.                 yylval.ival = '-' ;
  296.                 temp_buff.string_buff[0] = 
  297.                      temp_buff.string_buff[1] = '-' ;
  298.                 temp_buff.string_buff[2] = 0 ;
  299.                 ct_ret(INC_or_DEC) ;
  300.  
  301.             case  '=' :
  302.                 ct_ret(SUB_ASG) ;
  303.  
  304.             default :  un_next() ; ct_ret(MINUS) ;
  305.           }
  306.  
  307.       case  SC_COMMA :  eat_nl() ; ct_ret(COMMA) ;
  308.  
  309.       case  SC_MUL  :  test1_ret('=', MUL_ASG, MUL) ;
  310.       case  SC_DIV :   
  311.           { int *p = can_precede_re ;
  312.  
  313.             do
  314.                 if ( *p == current_token )
  315.                     ct_ret( collect_RE() ) ;
  316.             while ( *p++ != -1 ) ;
  317.  
  318.             test1_ret( '=', DIV_ASG , DIV ) ;
  319.           }
  320.  
  321.       case  SC_MOD  :  test1_ret('=', MOD_ASG, MOD) ;
  322.       case  SC_POW :   test1_ret('=' , POW_ASG, POW) ;
  323.       case  SC_LPAREN : 
  324.           paren_cnt++ ;
  325.           ct_ret(LPAREN) ;
  326.  
  327.       case  SC_RPAREN : 
  328.           if ( --paren_cnt < 0 )
  329.           { compile_error( "extra ')'" ) ;
  330.             paren_cnt = 0 ;
  331.             goto reswitch ; }
  332.  
  333.           ct_ret(RPAREN) ;
  334.  
  335.       case  SC_LBOX   : ct_ret(LBOX) ;
  336.       case  SC_RBOX   : ct_ret(RBOX) ;
  337.  
  338.       case  SC_MATCH  : ct_ret(MATCH) ;
  339.  
  340.       case  SC_EQUAL  :
  341.           test1_ret( '=', EQ, ASSIGN ) ;
  342.  
  343.       case  SC_NOT : /* !  */
  344.           test2_ret('=', NEQ, '~', NOT_MATCH, NOT ) ;
  345.  
  346.       case  SC_LT  :  /* '<' */
  347.           if ( getline_flag )
  348.           { getline_flag = 0 ; ct_ret(IO_IN) ; }
  349.           else
  350.           { ct_ret( ifnext('=', LTE , LT) ) ; }
  351.  
  352.       case  SC_GT  :  /* '>' */
  353.           if ( print_flag && paren_cnt == 0 )
  354.           { print_flag = 0 ;
  355.             /* there are 3 types of IO_OUT 
  356.                -- build the error string in temp_buff */
  357.             temp_buff.string_buff[0] = '>' ;
  358.             if ( next() == '>' ) 
  359.             { 
  360.               yylval.ival = F_APPEND ;
  361.               temp_buff.string_buff[1] = '>' ;
  362.               temp_buff.string_buff[2] =  0 ;
  363.             }
  364.             else
  365.             { un_next() ; 
  366.               yylval.ival = F_TRUNC ; 
  367.               temp_buff.string_buff[1] = 0 ;
  368.             }
  369.             return current_token = IO_OUT ;
  370.           }
  371.  
  372.           ct_ret( ifnext('=', GTE , GT) ) ;
  373.  
  374.       case  SC_OR :
  375.           if ( next() == '|' ) 
  376.           { eat_nl() ; ct_ret(brace_cnt?OR:P_OR) ; }
  377.           else 
  378.           { un_next() ; 
  379.  
  380.             if ( print_flag && paren_cnt == 0 )
  381.             { print_flag = 0 ; 
  382.               yylval.ival = PIPE_OUT;
  383.               temp_buff.string_buff[0] = '|' ;
  384.               temp_buff.string_buff[1] = 0 ;
  385.               ct_ret(IO_OUT) ;
  386.             }
  387.             else  ct_ret(PIPE) ;
  388.           }
  389.  
  390.       case  SC_AND :
  391.           if ( next() == '&' )  
  392.           { eat_nl() ; ct_ret(brace_cnt?AND:P_AND) ; }
  393.           else 
  394.           { un_next() ; yylval.ival = '&' ; ct_ret(UNEXPECTED) ; }
  395.  
  396.       case  SC_QMARK  :  ct_ret(QMARK) ;
  397.       case  SC_COLON  :  ct_ret(COLON) ;
  398.       case  SC_RBRACE :
  399.           if ( --brace_cnt < 0 )
  400.           { compile_error("extra '}'" ) ;
  401.             eat_semi_colon() ;
  402.             brace_cnt = 0 ; goto reswitch ; }
  403.  
  404.           if ( (c = current_token) == NL || c == SEMI_COLON 
  405.                || c == SC_FAKE_SEMI_COLON  || c == RBRACE  )
  406.           { 
  407.             /* if the brace_cnt is zero , we've completed
  408.                a pattern action block. If the user insists
  409.                on adding a semi-colon on the same line
  410.                we will eat it.  Note what we do below:
  411.                physical law -- conservation of semi-colons */
  412.  
  413.             if ( brace_cnt == 0 )  eat_semi_colon() ;
  414.             eat_nl() ;
  415.             ct_ret(RBRACE) ;
  416.           }
  417.  
  418.           /* supply missing semi-colon to statement that
  419.              precedes a '}' */
  420.           brace_cnt++ ; un_next() ;
  421.           current_token = SC_FAKE_SEMI_COLON ;
  422.           return  SEMI_COLON ;
  423.  
  424.       case  SC_DIGIT  :
  425.       case  SC_DOT    :
  426.           { double d ;
  427.             int flag ;
  428.  
  429.             if ( (d = collect_decimal(c, &flag)) == 0.0 )
  430.                 if ( flag )  ct_ret(flag) ;
  431.                 else  yylval.cp = &cell_zero ;
  432.             else if ( d == 1.0 ) yylval.cp = &cell_one ;
  433.             else 
  434.             { yylval.cp = new_CELL() ;
  435.               yylval.cp->type = C_DOUBLE ;
  436.               yylval.cp->dval = d ; 
  437.             }
  438.             ct_ret( CONSTANT ) ;
  439.           }
  440.  
  441.       case  SC_DOLLAR :  /* '$' */
  442.           { double d ;
  443.             int flag ;
  444.  
  445.             while ( scan_code[c = next()] == SC_SPACE )  ;
  446.             if ( scan_code[c] != SC_DIGIT &&
  447.                  scan_code[c] != SC_DOT )
  448.             { un_next() ; ct_ret(DOLLAR) ; }
  449.             /* compute field address at compile time */
  450.             if ( (d = collect_decimal(c, &flag)) == 0.0 )
  451.                 if ( flag )  ct_ret(flag) ; /* an error */
  452.                 else  yylval.cp = &field[0] ;
  453.             else
  454.             { int k = (int) d ;
  455.  
  456.               if ( k > MAX_FIELD )
  457.               { compile_error(
  458.                    "maximum field index(%d) exceeded" , k ) ;
  459.                 k = MAX_FIELD ;
  460.               }
  461.               else  yylval.cp = &field[k] ;
  462.             }
  463.  
  464.             ct_ret(FIELD) ;
  465.           }
  466.  
  467.       case  SC_DQUOTE :
  468.           return current_token = collect_string() ;
  469.  
  470.       case  SC_IDCHAR : /* collect an identifier */
  471.             { unsigned char *p =
  472.                     (unsigned char *)temp_buff.string_buff + 1 ;
  473.               SYMTAB *stp ;
  474.  
  475.               temp_buff.string_buff[0] = c ;
  476.  
  477.               while ( 
  478.                 (c = scan_code[ *p++ = next()]) == SC_IDCHAR ||
  479.                        c == SC_DIGIT )  ;
  480.               
  481.               un_next() ; * --p = 0 ;
  482.  
  483.               switch( (stp = find(temp_buff.string_buff))->type )
  484.               { case ST_NONE :  
  485.                   /* check for function call before defined */
  486.                       if ( next() == '(' )
  487.                       { stp->type = ST_FUNCT ;
  488.                         stp->stval.fbp = (FBLOCK *)
  489.                                 zmalloc(sizeof(FBLOCK)) ;
  490.                         stp->stval.fbp->name = stp->name ;
  491.                         stp->stval.fbp->code = (INST *) 0 ;
  492.                         yylval.fbp = stp->stval.fbp ;
  493.                         current_token = FUNCT_ID ;
  494.                       }
  495.                       else
  496.                       { yylval.stp = stp ;
  497.                         current_token = ID ;
  498.                       }
  499.                       un_next() ;
  500.                       break ;
  501.  
  502.             case  ST_NR  :
  503.               NR_reference = 1 ;
  504.               stp->type = ST_VAR ;
  505.               /* fall thru */
  506.                         
  507.                 case ST_VAR :
  508.                 case  ST_ARRAY :
  509.                 case  ST_LOCAL_NONE :
  510.                 case  ST_LOCAL_VAR :
  511.                 case  ST_LOCAL_ARRAY :
  512.  
  513.                       yylval.stp = stp ;
  514.                       current_token = ID ;
  515.                       break ;
  516.  
  517.                 case ST_FUNCT :
  518.                       yylval.fbp = stp->stval.fbp ;
  519.                       current_token = FUNCT_ID ;
  520.                       break ;
  521.  
  522.                 case ST_KEYWORD :  
  523.                       current_token = stp->stval.kw ;
  524.                       break ;
  525.  
  526.                 case  ST_BUILTIN :
  527.                       yylval.bip = stp->stval.bip ;
  528.                       current_token = BUILTIN ;
  529.                       break ;
  530.  
  531.                 case  ST_FIELD  :
  532.                       yylval.cp = stp->stval.cp ;
  533.                       current_token = FIELD ;
  534.                       break ;
  535.  
  536.                 case  ST_LENGTH  :
  537.                     { CELL *bi_length() ;
  538.                       static BI_REC length_bi_rec =
  539.                       { "length", bi_length, 1, 1 } ;
  540.  
  541.                       while ( scan_code[ c = next() ] == SC_SPACE ) ;
  542.                       un_next() ;
  543.  
  544.                       if ( c == '(' )
  545.                       { yylval.bip = &length_bi_rec ;
  546.                         current_token = BUILTIN ;
  547.                       }
  548.                       else current_token = LENGTH ;
  549.                     }
  550.                     break ;
  551.  
  552.                 default : 
  553.                       bozo("find returned bad st type") ;
  554.               }
  555.               return  current_token  ;
  556.             }
  557.  
  558.  
  559.       case  SC_UNEXPECTED :
  560.             yylval.ival = c & 0xff ;
  561.             ct_ret(UNEXPECTED) ;
  562.     }
  563.     return  0 ; /* never get here make lint happy */
  564. }
  565.  
  566. /* collect a decimal constant in temp_buff.
  567.    Return the value and error conditions by reference */
  568.  
  569. static double collect_decimal(c, flag)
  570.   int c ; int *flag ;
  571. { register unsigned char *p = (unsigned char*) temp_buff.string_buff + 1;
  572.   unsigned char *endp ;
  573.   double d ;
  574.  
  575.   *flag = 0 ;
  576.   temp_buff.string_buff[0] = c ;
  577.  
  578.   if ( c == '.' )
  579.   { if ( scan_code[*p++ = next()] != SC_DIGIT )
  580.     { *flag = UNEXPECTED ; yylval.ival = '.' ;
  581.       return 0.0 ; }
  582.   }
  583.   else
  584.   {  while ( scan_code[*p++ = next()] == SC_DIGIT ) ;
  585.      if ( p[-1] != '.' )
  586.      { un_next() ; p-- ; }
  587.   }
  588.   /* get rest of digits after decimal point */
  589.   while ( scan_code[*p++ = next()] == SC_DIGIT )  ;
  590.  
  591.   /* check for exponent */
  592.   if ( p[-1] != 'e' && p[-1] != 'E' )
  593.   { un_next() ; * --p = 0 ; }
  594.   else  /* get the exponent */
  595.     if ( scan_code[*p = next()] != SC_DIGIT &&
  596.          *p != '-' && *p != '+' )
  597.     { *++p = 0 ; *flag = BAD_DECIMAL ;
  598.       return 0.0 ; }
  599.     else  /* get the rest of the exponent */
  600.     { p++ ;
  601.       while ( scan_code[*p++ = next()] == SC_DIGIT )  ;
  602.       un_next() ; * --p = 0 ;
  603.     }
  604.  
  605.   errno = 0 ; /* check for overflow/underflow */
  606.   d = strtod( temp_buff.string_buff, (char **)&endp ) ;
  607.  
  608. #ifndef  STRTOD_UNDERFLOW_ON_ZERO_BUG
  609.   if ( errno )
  610.       compile_error( "%s : decimal %sflow" , temp_buff.string_buff,
  611.         d == 0.0 ? "under" : "over") ;
  612. #else /* sun4 bug */
  613.   if ( errno && d != 0.0 )
  614.       compile_error( "%s : decimal overflow", temp_buff.string_buff) ;
  615. #endif
  616.  
  617.   if ( endp != p )
  618.   { *flag = BAD_DECIMAL ; return 0.0 ; }
  619.   return d ;
  620. }
  621.  
  622. /*----------  process escape characters ---------------*/
  623.  
  624. static char hex_val['f' - 'A' + 1] = {
  625. 10,11,12,13,14,15, 0, 0,
  626.  0, 0, 0, 0, 0, 0, 0, 0,
  627.  0, 0, 0, 0, 0, 0, 0, 0,
  628.  0, 0, 0, 0, 0, 0, 0, 0,
  629. 10,11,12,13,14,15 } ;
  630.  
  631. #define isoctal(x)  ((x)>='0'&&(x)<='7')
  632.  
  633. #define  hex_value(x)   hex_val[(x)-'A']
  634.  
  635. #define ishex(x) (scan_code[x] == SC_DIGIT ||\
  636.                   'A' <= (x) && (x) <= 'f' && hex_value(x))
  637.  
  638. static int PROTO(octal, (char **)) ;
  639. static int PROTO(hex, (char **)) ;
  640.  
  641. /* process one , two or three octal digits
  642.    moving a pointer forward by reference */
  643. static int octal( start_p )
  644.   char **start_p ;
  645. { register char *p = *start_p ;
  646.   register unsigned x ;
  647.  
  648.   x = *p++ - '0' ;
  649.   if ( isoctal(*p) )
  650.   {
  651.     x = (x<<3) + *p++ - '0' ;
  652.     if ( isoctal(*p) )   x = (x<<3) + *p++ - '0' ;
  653.   }
  654.   *start_p = p ;
  655.   return  x & 0xff ;
  656. }
  657.  
  658. /* process one or two hex digits
  659.    moving a pointer forward by reference */
  660.  
  661. static int  hex( start_p )
  662.   char **start_p ;
  663. { register unsigned char *p = (unsigned char*) *start_p ;
  664.   register unsigned x ;
  665.   unsigned t ;
  666.  
  667.   if ( scan_code[*p] == SC_DIGIT )
  668.         x = *p++ - '0' ;
  669.   else  x = hex_value(*p++) ;
  670.  
  671.   if ( scan_code[*p] == SC_DIGIT )
  672.         x = (x<<4) + *p++ - '0' ;
  673.   else
  674.   if ( 'A' <= *p && *p <= 'f' && (t = hex_value(*p)) )
  675.   { x = (x<<4) + t ; p++ ; }
  676.  
  677.   *start_p = (char *) p ;
  678.   return x ;
  679. }
  680.  
  681. #define  ET_END     9
  682.  
  683. static struct { char in , out ; } escape_test[ET_END+1] = {
  684. 'n' , '\n',
  685. 't' , '\t',
  686. 'f' , '\f',
  687. 'b' , '\b',
  688. 'r' , '\r',
  689. 'a' , '\07',
  690. 'v' , '\013',
  691. '\\', '\\',
  692. '\"', '\"',
  693. 0 , 0 } ;
  694.  
  695.  
  696. /* process the escape characters in a string, in place . */
  697.  
  698. char *rm_escape(s)
  699.   char *s ;
  700. { register char *p, *q ;
  701.   char *t ;
  702.   int i ;
  703.  
  704.   q = p = s ;
  705.  
  706.   while ( *p )
  707.       if ( *p == '\\' )
  708.       { 
  709.     escape_test[ET_END].in = * ++p ; /* sentinal */
  710.     i = 0 ;
  711.     while ( escape_test[i].in != *p )  i++ ;
  712.  
  713.     if ( i != ET_END )  /* in table */
  714.         { 
  715.           p++ ; *q++ = escape_test[i].out ;
  716.         }
  717.         else
  718.         if ( isoctal(*p) ) 
  719.         {
  720.           t = p ;  *q++ = octal(&t) ; p = t ;
  721.         }
  722.         else
  723.         if ( *p == 'x' && ishex(*(unsigned char*)(p+1)) )
  724.         {
  725.           t = p+1 ; *q++ = hex(&t) ; p = t ;
  726.         }
  727.     else
  728.     if ( *p == 0 ) /* can only happen with command line assign */
  729.         *q++ = '\\' ;
  730.         else  /* not an escape sequence */
  731.         { 
  732.           *q++ = '\\' ; *q++ = *p++ ;
  733.         }
  734.       }
  735.       else  *q++ = *p++ ;
  736.  
  737.   *q = 0 ;
  738.   return s ;
  739. }
  740.  
  741. static  int  collect_string()
  742. { register unsigned char *p = (unsigned char *)temp_buff.string_buff ;
  743.   int c ;
  744.   int e_flag = 0 ; /* on if have an escape char */
  745.  
  746.   while ( 1 )
  747.       switch( scan_code[ *p++ = next() ] )
  748.       { case  SC_DQUOTE : /* done */
  749.               * --p = 0 ;  goto out ;
  750.  
  751.         case  SC_NL :
  752.               p[-1] = 0 ;
  753.               /* fall thru */
  754.  
  755.         case  0 :   /* unterminated string */
  756.               compile_error(
  757.               "runaway string constant \"%.10s ..." ,
  758.               temp_buff.string_buff, token_lineno ) ;
  759.               mawk_exit(1) ;
  760.  
  761.         case SC_ESCAPE :
  762.               if ( (c = next()) == '\n' )
  763.               { p-- ; lineno++ ; }
  764.               else  
  765.                 if ( c == 0 )  un_next() ;   
  766.                 else 
  767.                 { *p++ = c ; e_flag = 1 ; }
  768.  
  769.               break ;
  770.  
  771.         default : break ;
  772.       }
  773.  
  774. out:
  775.     yylval.cp = new_CELL() ;
  776.     yylval.cp->type = C_STRING ;
  777.     yylval.cp->ptr = (PTR) new_STRING(
  778.          e_flag ? rm_escape( temp_buff.string_buff ) 
  779.                 : temp_buff.string_buff ) ;
  780.     return  CONSTANT ;
  781. }
  782.  
  783.  
  784. static  int  collect_RE()
  785. { register unsigned char *p = (unsigned char*) temp_buff.string_buff ;
  786.   int c ;
  787.   STRING *sval ;
  788.  
  789.   while ( 1 )
  790.       switch( scan_code[ *p++ = next() ] )
  791.       { case  SC_DIV : /* done */
  792.               * --p = 0 ;  goto out ;
  793.  
  794.         case  SC_NL :
  795.               p[-1] = 0 ;
  796.               /* fall thru */
  797.  
  798.         case  0 :   /* unterminated re */
  799.               compile_error(
  800.               "runaway regular expression /%.10s ..." ,
  801.               temp_buff.string_buff, token_lineno ) ;
  802.               mawk_exit(1) ;
  803.  
  804.         case SC_ESCAPE :
  805.               switch( c = next() )
  806.               { case '/' :  
  807.                       p[-1] = '/' ; break ;
  808.  
  809.                 case '\n' :
  810.                       p-- ;  break ;
  811.  
  812.                 case  0   :
  813.                       un_next() ;  break ;
  814.  
  815.                 default :
  816.                       *p++ = c ; break ;
  817.               }
  818.               break ;
  819.       }
  820.  
  821. out:
  822.   /* now we've got the RE, so compile it */
  823.   sval = new_STRING( temp_buff.string_buff ) ;
  824.   yylval.cp = new_CELL() ;
  825.   yylval.cp->type = C_RE ;
  826.   yylval.cp->ptr = re_compile(sval) ;
  827.   free_STRING(sval) ;
  828.   return RE ;
  829. }
  830.  
  831.